﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using Win104.Common;
using Win104.IEC104;
using Win104.Tools;
using Win104.ZZH;

namespace Win104
{
    /// <summary>
    /// 微信联系：xiaoyiyz
    /// 
    /// 专注电力、光伏、物联网行业
    /// 
    /// 技术交流、项目合作（功能模块开发、系统实施运维、项目紧急救援）
    /// </summary>
    public partial class Form1 : Form
    {
        IPEndPoint _endPoint;
        TcpSocketClient _tcpClient;
        /// <summary>
        /// 用于业务逻辑处理
        /// </summary>
        System.Timers.Timer loopTimer = new System.Timers.Timer();
        /// <summary>
        /// 用于遥调遥控
        /// </summary>
        System.Timers.Timer controlTimer = new System.Timers.Timer();
        /// <summary>
        /// 接收序号
        /// </summary>
        public int ReceiveSeqNum = 0; 
        /// <summary>
        /// 发送序号，每发送一个后需+1
        /// </summary>
        public int SendSeqNum = 0; 

        public Form1()
        {
            InitializeComponent();

            this.listView1.View = View.Details;
            this.listView1.Columns.Add("", 50, HorizontalAlignment.Center);
            this.listView1.Columns.Add("数量", 50, HorizontalAlignment.Center);
            this.listView1.Columns.Add("时间戳", 150, HorizontalAlignment.Center);

            loopTimer.Interval = 10*1000;
            loopTimer.Elapsed += LoopTimer_Elapsed;

            //遥控遥调的时间设置为2秒一次轮询
            controlTimer.Interval = 2 * 1000;
            controlTimer.Elapsed += ControlTimer_Elapsed;
        }

        //这里可以执行一些定时任务，10秒轮询一次，时间间隔可调整
        private void LoopTimer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
        {
            try
            {
                this.loopTimer.Enabled = false;

                //每5分钟发送一次总召
                if(DateTime.Now.Minute % 5 == 0)
                {
                    SendCall();
                }

                UpdateListView();

                //定时任务业务逻辑可在此执行
                /////////////
            }
            catch (Exception ex)
            {
                AddListBoxItem(ex.Message);
            }
            finally
            {
                this.loopTimer.Enabled = true;
            }
        }

        //遥调和遥控
        private void ControlTimer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
        {
            try
            {
                this.controlTimer.Enabled = false;
                
                //模拟从数据库或配置文件读取
                //遥调
                List<AdjustModel> adjusts = new List<AdjustModel>();
                foreach (AdjustModel adjust in adjusts)
                {
                    if (Config104.RemoteAdjustHash.ContainsKey(adjust.Address) && Math.Abs(adjust.Value - double.Parse(Config104.RemoteAdjustHash[adjust.Address].ToString())) < 0.01)
                    {
                        //包含并且相等或差值小于指定范围，不控制
                    }
                    else
                    {
                        //添加或更新键值对
                        Config104.RemoteAdjustHash.AddOrUpdate(adjust.Address, adjust.Value, null);

                        if (this.checkBox2.Checked)
                        {
                            // 起始位
                            string start = "68";
                            // 长度
                            int len = 16;
                            byte[] lenNum = new byte[1];
                            lenNum[0] = (byte)(len >> 0);
                            string lenStr = ConvertHelper.ToHexString(lenNum);
                            // 发送序号
                            byte[] sendNum = new byte[2];
                            sendNum[0] = (byte)(SendSeqNum << 1);
                            sendNum[1] = (byte)(SendSeqNum >> 7);
                            SendSeqNum += 1;
                            string sendStr = ConvertHelper.ToHexString(sendNum);
                            // 接收序号
                            byte[] recNum = new byte[2];
                            recNum[0] = (byte)(ReceiveSeqNum << 1);
                            recNum[1] = (byte)(ReceiveSeqNum >> 7);
                            string recStr = ConvertHelper.ToHexString(recNum);
                            // 类型标识
                            string typeIdStr = "31";
                            // 可变结构限定词
                            string vsqStr = "01";
                            // 传输原因
                            string causeOfTransmissionStr = "0600";
                            // 公共地址
                            string commAddressStr = "0100";
                            // 信息体地址
                            int addr = int.Parse(adjust.Address);
                            byte[] addrNum = new byte[3];
                            addrNum[0] = (byte)(addr >> 0);
                            addrNum[1] = (byte)(addr >> 8);
                            addrNum[2] = (byte)(addr >> 16);
                            string addrStr = ConvertHelper.ToHexString(addrNum);
                            // 信息值2位
                            byte[] valueNum = new byte[2];
                            valueNum[0] = (byte)((int)adjust.Value >> 0);
                            valueNum[1] = (byte)((int)adjust.Value >> 8);
                            string valuestr = ConvertHelper.ToHexString(valueNum);
                            // 品质因素1位 
                            string QDSStr = "00";
                            SendToServer(start + lenStr + sendStr + recStr +
                                    typeIdStr + vsqStr + causeOfTransmissionStr + commAddressStr +
                                    addrStr + valuestr + QDSStr);
                            WriteLog.WriteLogs("发送遥调命令帧：" + start + lenStr + sendStr + recStr +
                                    typeIdStr + vsqStr + causeOfTransmissionStr + commAddressStr +
                                    addrStr + valuestr);
                            AddListBoxItem("发送遥调命令" + adjust.Address + ":" + adjust.Value);
                            Task.Delay(200).Wait();
                        }
                    }
                }

                //遥控
                List<ControlModel> controls = new List<ControlModel>();
                foreach (ControlModel control in controls)
                {
                    if (Config104.RemoteControlHash.ContainsKey(control.Address) && control.Value == double.Parse(Config104.RemoteControlHash[control.Address].ToString()))
                    {
                        //包含并且相等，不控制
                    }
                    else
                    {
                        //添加或更新键值对
                        Config104.RemoteControlHash.AddOrUpdate(control.Address, control.Value, null);
                        
                        if (this.checkBox2.Checked)
                        {
                            // 起始位
                            string start = "68";
                            // 长度
                            int len = 14;
                            byte[] lenNum = new byte[1];
                            lenNum[0] = (byte)(len >> 0);
                            string lenStr = ConvertHelper.ToHexString(lenNum);
                            // 发送序号
                            byte[] sendNum = new byte[2];
                            sendNum[0] = (byte)(SendSeqNum << 1);
                            sendNum[1] = (byte)(SendSeqNum >> 7);
                            SendSeqNum += 1;
                            string sendStr = ConvertHelper.ToHexString(sendNum);
                            // 接收序号
                            byte[] recNum = new byte[2];
                            recNum[0] = (byte)(ReceiveSeqNum << 1);
                            recNum[1] = (byte)(ReceiveSeqNum >> 7);
                            string recStr = ConvertHelper.ToHexString(recNum);
                            // 类型标识
                            string typeIdStr = "2d";
                            // 可变结构限定词
                            string vsqStr = "01";
                            // 传输原因
                            string causeOfTransmissionStr = "0600";
                            // 公共地址
                            string commAddressStr = "0100";
                            // 信息体地址
                            int addr = int.Parse(control.Address);
                            byte[] addrNum = new byte[3];
                            addrNum[0] = (byte)(addr >> 0);
                            addrNum[1] = (byte)(addr >> 8);
                            addrNum[2] = (byte)(addr >> 16);
                            string addrStr = ConvertHelper.ToHexString(addrNum);
                            // 信息值
                            byte[] valueNum = new byte[1];
                            valueNum[0] = (byte)(control.Value >> 0);
                            string valuestr = ConvertHelper.ToHexString(valueNum);
                            SendToServer(start + lenStr + sendStr + recStr +
                                    typeIdStr + vsqStr + causeOfTransmissionStr + commAddressStr +
                                    addrStr + valuestr);
                            WriteLog.WriteLogs("发送遥控命令帧：" + start + lenStr + sendStr + recStr +
                                    typeIdStr + vsqStr + causeOfTransmissionStr + commAddressStr +
                                    addrStr + valuestr);
                            AddListBoxItem("发送遥控命令" + control.Address + ":" + control.Value);
                            Task.Delay(200).Wait();
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                AddListBoxItem("遥调遥控："+ex.Message);
            }
            finally
            {
                this.controlTimer.Enabled =true;
            }
        }
        
        //连接按钮事件
        private void button1_Click(object sender, EventArgs e)
        {
            if ("连接".Equals(this.button1.Text))
            {
                try
                {
                    ConnectServer();
                    loopTimer.Start();
                    controlTimer.Start();
                    this.button1.Text = "断开";
                }
                catch
                {
                    AddListBoxItem("链接失败！");
                }
            }
            else
            {
                Disconnect();
                loopTimer.Stop();
                controlTimer.Stop();
                AddListBoxItem("已断开链接");
                this.button1.Text = "连接";
            }
        }

        /// <summary>
        /// 链接服务端
        /// </summary>
        void ConnectServer()
        {
            string ip = this.textBox1.Text.Trim();
            if (string.IsNullOrEmpty(ip))
                return;
            string port = this.textBox2.Text.Trim();
            if (string.IsNullOrWhiteSpace(port))
                return;

            _endPoint = new IPEndPoint(IPAddress.Parse(ip), int.Parse(port));
            var configuration = new TcpSocketClientConfiguration();

            _tcpClient = new TcpSocketClient(_endPoint, configuration);
            _tcpClient.ServerConnected += _tcpClient_ServerConnected;
            _tcpClient.ServerDisconnected += _tcpClient_ServerDisconnected;
            _tcpClient.ServerDataReceived += _tcpClient_ServerDataReceived;
            _tcpClient.Connect();
            AddListBoxItem("连接成功");
            //发送启动帧
            SendToServer("680407000000");

        }

        /// <summary>
        /// 发送总召
        /// </summary>
        void SendCall()
        {
            try
            {
                byte[] recNum = new byte[2];
                recNum[0] = (byte)(ReceiveSeqNum << 1);
                recNum[1] = (byte)(ReceiveSeqNum >> 7);
                string recStr = ConvertHelper.ToHexString(recNum);
                byte[] sendNum = new byte[2];
                sendNum[0] = (byte)(SendSeqNum << 1);
                sendNum[1] = (byte)(SendSeqNum >> 7);
                SendSeqNum += 1;
                string sendStr = ConvertHelper.ToHexString(sendNum);
                SendToServer("680E" + sendStr + recStr + "64010600010000000014");
            }
            catch (Exception ex)
            {
                AddListBoxItem(ex.Message);
            }
        }

        /// <summary>
        /// 发送至服务端
        /// </summary>
        /// <param name="msg"></param>
        void SendToServer(string msg)
        {
            if(_tcpClient !=null && _tcpClient.State == SocketConnectionState.Connected)
            {
                _tcpClient.Send(ConvertHelper.HexToBytes(msg));
            }
            else
            {
                Disconnect();
                AddListBoxItem("请先连接服务");
            }
        }

        /// <summary>
        /// Socket DataReceived事件
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void _tcpClient_ServerDataReceived(object sender, TcpServerDataReceivedEventArgs e)
        {
            try
            {
                Apdu apdu = new Apdu(new ByteBody(e.Data.Take(e.DataLength).ToArray()));
                if(apdu.GetApciType() == ApciType.I_FORMAT)
                {
                    Asdu asdu = apdu.GetAsdu();
                    //处理I数据帧
                    HandleData(asdu.GetTypeId(), asdu.GetInformationObjects());

                    //返回S确认命令
                    ReceiveSeqNum = apdu.GetSendSeqNumber() + 1;
                    byte[] recNum = new byte[2];
                    recNum[0] = (byte)(ReceiveSeqNum << 1);
                    recNum[1] = (byte)(ReceiveSeqNum >> 7);
                    SendToServer("68040100" + ConvertHelper.ToHexString(recNum));
                }
                else if(apdu.GetApciType() == ApciType.U_START_CON)
                {
                    AddListBoxItem("确认启动消息，U类型");
                    SendCall();
                    AddListBoxItem("已发送总召");
                }
                else if(apdu.GetApciType() == ApciType.U_STOP_ACT)
                {
                    SendToServer("680423000000");
                    AddListBoxItem("确认停止消息，U类型");
                }
                else if (apdu.GetApciType() == ApciType.U_TEST_ACT)
                {
                    SendToServer("680483000000");
                    AddListBoxItem("确认测试消息，U类型");
                }
                else
                {
                    AddListBoxItem("其他报文：" + apdu.GetApciType());
                }

            }
            catch (Exception ex)
            {
                AddListBoxItem("异常：" + ex.Message);
                
            }

        }

        //断开事件
        private void _tcpClient_ServerDisconnected(object sender, TcpServerDisconnectedEventArgs e)
        {
            AddListBoxItem("服务端断开链接：" + e.RemoteEndPoint.ToString());
            _tcpClient.Close();
        }

        //连接事件
        private void _tcpClient_ServerConnected(object sender, TcpServerConnectedEventArgs e)
        {
            AddListBoxItem("已连接到服务端：" + e.RemoteEndPoint.ToString());
        }


        //解析数据
        void HandleData(int typeId, InformationObject[] infoObjs)
        {
            StringBuilder sb = new StringBuilder();
            for (int i = 0; i < infoObjs.Length; i++)
            {
                //浮点遥测值
                if (typeId == 13)
                {
                    int firstAddress = infoObjs[i].GetInformationObjectAddress();  // 信息地址起始位
                    int len = infoObjs[i].GetInformationElements().Length / 2;
                    for (int j = 0; j < len; j++)
                    {
                        int address = firstAddress + j;
                        if (address < 16385 || address > 17000)
                        {
                            Console.WriteLine("遥测信息地址超出定义范围");
                        }
                        var value = infoObjs[i].GetInformationElements()[j, 0];

                        var kv = "k:" + address + ",v:" + value + "\r\n";
                        sb.Append(kv);
                        Config104.InsertHash(address, ((EShortFloat)value).GetValue());
                        
                    }
                }
                //单点遥信
                else if (typeId == 1)
                {
                    int firstAddress = infoObjs[i].GetInformationObjectAddress();  // 信息地址起始位
                    int len = infoObjs[i].GetInformationElements().Length;   // 所有信息值长度
                    for (int j = 0; j < len; j++)
                    {
                        int address = firstAddress + j;
                        if (address > 500 || address < 0)
                        {
                            Console.WriteLine("遥信信息超出定义范围：" + address);
                        }
                        var value = infoObjs[i].GetInformationElements()[j, 0];

                        var kv = "k:" + address + ",v:" + value + "\r\n";
                        sb.Append(kv);
                        Config104.InsertHash(address, ((ESinglePointWithQuality)value).IsOn());
                    }
                }
            }
            if(checkBox1.Checked)
                WriteLog.WriteLogs(sb.ToString());
        }

        void Disconnect()
        {
            if (_tcpClient != null)
                _tcpClient.Close();

            this.button1.Text = "连接";
        }

        private void UpdateListView()
        {
            this.Invoke(new Action(() =>
            {
                if (this.listView1.Items.Count > 0)
                    this.listView1.Items.Clear();
                this.listView1.BeginUpdate();

                ListViewItem lvItem = new ListViewItem();
                lvItem.Text = "";
                lvItem.SubItems.Add(new ListViewItem.ListViewSubItem(lvItem, Config104.GetHashCount() + ""));
                lvItem.SubItems.Add(new ListViewItem.ListViewSubItem(lvItem, Config104.UpdateTime + ""));
                listView1.Items.Add(lvItem);

                this.listView1.EndUpdate();
            }));
        }

        void AddListBoxItem(string msg)
        {
            if (this.listBox1.InvokeRequired)
            {
                this.Invoke(new Action(() =>
                {
                    if (this.listBox1.Items.Count > 100)
                        this.listBox1.Items.Clear();
                    this.listBox1.Items.Add(msg);
                }));
            }
            else
            {
                this.listBox1.Items.Add(msg);
            }
        }

        //窗体关闭事件
        private void Form1_FormClosing(object sender, FormClosingEventArgs e)
        {
            loopTimer.Stop();
            controlTimer.Stop();
            Disconnect();
        }

    }
}
